// // Real-time speech recognition of input from a microphone
// //
// // A very quick-n-dirty implementation serving mainly as a proof of concept.
// //
// #include "whisper.cpp/examples/common-sdl.h"
// #include "whisper.cpp/examples/common.h"
// #include "whisper.cpp/examples/common-whisper.h"
// #include "whisper.h"

// #include <chrono>
// #include <cstdio>
// #include <fstream>
// #include <string>
// #include <thread>
// #include <vector>

// // command-line parameters
// // whisper 语音识别的参数
// struct whisper_params {
//     int32_t n_threads  = std::min(4, (int32_t) std::thread::hardware_concurrency());
//     int32_t step_ms    = 3000;
//     int32_t length_ms  = 10000;
//     int32_t keep_ms    = 200;
//     int32_t capture_id = -1;
//     int32_t max_tokens = 32;
//     int32_t audio_ctx  = 0;
//     int32_t beam_size  = -1;

//     float vad_thold    = 0.6f;
//     float freq_thold   = 100.0f;

//     bool translate     = false;
//     bool no_fallback   = false;
//     bool print_special = false;
//     bool no_context    = true;
//     bool no_timestamps = false;
//     bool tinydiarize   = false;
//     bool save_audio    = false; // save audio to wav file
//     bool use_gpu       = true;
//     bool flash_attn    = false;

//     std::string language  = "en";
//     std::string model     = "models/ggml-base.en.bin";
//     std::string fname_out;
// };


// int main(int argc, char ** argv) {
//     whisper_params params;  // whisper 语音识别的参数

//     if (whisper_params_parse(argc, argv, params) == false) {
//         return 1;
//     }

//     params.keep_ms   = std::min(params.keep_ms,   params.step_ms);
//     params.length_ms = std::max(params.length_ms, params.step_ms);

//     const int n_samples_step = (1e-3*params.step_ms  )*WHISPER_SAMPLE_RATE;
//     const int n_samples_len  = (1e-3*params.length_ms)*WHISPER_SAMPLE_RATE;
//     const int n_samples_keep = (1e-3*params.keep_ms  )*WHISPER_SAMPLE_RATE;
//     const int n_samples_30s  = (1e-3*30000.0         )*WHISPER_SAMPLE_RATE;

//     const bool use_vad = n_samples_step <= 0; // sliding window mode uses VAD

//     const int n_new_line = !use_vad ? std::max(1, params.length_ms / params.step_ms - 1) : 1; // number of steps to print new line

//     params.no_timestamps  = !use_vad;
//     params.no_context    |= use_vad;
//     params.max_tokens     = 0;

//     // init audio

//     audio_async audio(params.length_ms);
//     if (!audio.init(params.capture_id, WHISPER_SAMPLE_RATE)) {
//         fprintf(stderr, "%s: audio.init() failed!\n", __func__);
//         return 1;
//     }

//     audio.resume();

//     // whisper init
//     if (params.language != "auto" && whisper_lang_id(params.language.c_str()) == -1){
//         fprintf(stderr, "error: unknown language '%s'\n", params.language.c_str());
//         whisper_print_usage(argc, argv, params);
//         exit(0);
//     }

//     struct whisper_context_params cparams = whisper_context_default_params();

//     cparams.use_gpu    = params.use_gpu;
//     cparams.flash_attn = params.flash_attn;

//     struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams);

//     std::vector<float> pcmf32    (n_samples_30s, 0.0f);
//     std::vector<float> pcmf32_old;
//     std::vector<float> pcmf32_new(n_samples_30s, 0.0f);

//     std::vector<whisper_token> prompt_tokens;

//     // print some info about the processing
//     {
//         fprintf(stderr, "\n");
//         if (!whisper_is_multilingual(ctx)) {
//             if (params.language != "en" || params.translate) {
//                 params.language = "en";
//                 params.translate = false;
//                 fprintf(stderr, "%s: WARNING: model is not multilingual, ignoring language and translation options\n", __func__);
//             }
//         }
//         fprintf(stderr, "%s: processing %d samples (step = %.1f sec / len = %.1f sec / keep = %.1f sec), %d threads, lang = %s, task = %s, timestamps = %d ...\n",
//                 __func__,
//                 n_samples_step,
//                 float(n_samples_step)/WHISPER_SAMPLE_RATE,
//                 float(n_samples_len )/WHISPER_SAMPLE_RATE,
//                 float(n_samples_keep)/WHISPER_SAMPLE_RATE,
//                 params.n_threads,
//                 params.language.c_str(),
//                 params.translate ? "translate" : "transcribe",
//                 params.no_timestamps ? 0 : 1);

//         if (!use_vad) {
//             fprintf(stderr, "%s: n_new_line = %d, no_context = %d\n", __func__, n_new_line, params.no_context);
//         } else {
//             fprintf(stderr, "%s: using VAD, will transcribe on speech activity\n", __func__);
//         }

//         fprintf(stderr, "\n");
//     }

//     int n_iter = 0;

//     bool is_running = true;

//     std::ofstream fout;
//     if (params.fname_out.length() > 0) {
//         fout.open(params.fname_out);
//         if (!fout.is_open()) {
//             fprintf(stderr, "%s: failed to open output file '%s'!\n", __func__, params.fname_out.c_str());
//             return 1;
//         }
//     }

//     wav_writer wavWriter;
//     // save wav file
//     if (params.save_audio) {
//         // Get current date/time for filename
//         time_t now = time(0);
//         char buffer[80];
//         strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", localtime(&now));
//         std::string filename = std::string(buffer) + ".wav";

//         wavWriter.open(filename, WHISPER_SAMPLE_RATE, 16, 1);
//     }
//     printf("[Start speaking]\n");
//     fflush(stdout);

//     auto t_last  = std::chrono::high_resolution_clock::now();
//     const auto t_start = t_last;

//     // main audio loop
//     while (is_running) {
//         if (params.save_audio) {
//             wavWriter.write(pcmf32_new.data(), pcmf32_new.size());
//         }
//         // handle Ctrl + C
//         is_running = sdl_poll_events();

//         if (!is_running) {
//             break;
//         }

//         // process new audio

//         // 不使用 vad 端点检测
//         if (!use_vad) {
//             while (true) {
//                 // handle Ctrl + C
//                 is_running = sdl_poll_events();
//                 if (!is_running) {  // 等于true的话跳出循环
//                     break;
//                 }


//                 // 获取 最新一段音频数据, 长度为 params.step_ms 毫秒，并存储在 pcmf32_new 里
//                 audio.get(params.step_ms, pcmf32_new);

//                 if ((int) pcmf32_new.size() > 2*n_samples_step) {
//                     fprintf(stderr, "\n\n%s: WARNING: cannot process audio fast enough, dropping audio ...\n\n", __func__);
//                     audio.clear();
//                     continue;
//                 }

//                 if ((int) pcmf32_new.size() >= n_samples_step) {
//                     audio.clear();
//                     break;
//                 }

//                 std::this_thread::sleep_for(std::chrono::milliseconds(1));
//             }

//             const int n_samples_new = pcmf32_new.size();

//             // take up to params.length_ms audio from previous iteration
//             const int n_samples_take = std::min((int) pcmf32_old.size(), std::max(0, n_samples_keep + n_samples_len - n_samples_new));

//             //printf("processing: take = %d, new = %d, old = %d\n", n_samples_take, n_samples_new, (int) pcmf32_old.size());

//             // 合并新旧音频
//             pcmf32.resize(n_samples_new + n_samples_take);

//             for (int i = 0; i < n_samples_take; i++) {
//                 pcmf32[i] = pcmf32_old[pcmf32_old.size() - n_samples_take + i];
//             }

//             memcpy(pcmf32.data() + n_samples_take, pcmf32_new.data(), n_samples_new*sizeof(float));

//             pcmf32_old = pcmf32;
//         } else {
//             // 记录当前时间
//             const auto t_now  = std::chrono::high_resolution_clock::now(); // 记录当前时间
//             // 记录 时间差
//             const auto t_diff = std::chrono::duration_cast<std::chrono::milliseconds>(t_now - t_last).count();

//             if (t_diff < 2000) {
//                 // 距离上次处理时间不够2秒，等待100ms，跳过识别
//                 std::this_thread::sleep_for(std::chrono::milliseconds(100));

//                 continue;
//             }

//             // 获取最近两秒的音频数据，存放到 pcmf32_new
//             audio.get(2000, pcmf32_new);

//             // 在上面获取的两秒的语音中检查1秒中是否有语音
//             if (::vad_simple(pcmf32_new, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, false)) {
                
//                 // 如果有语音的话，就获取arams.length_ms 长度的语音存放到 pcmf32
//                 audio.get(params.length_ms, pcmf32);
//             } else {

//                 // 如果最近的两秒钟没有检测到语音，那么就继续等待100毫秒
//                 std::this_thread::sleep_for(std::chrono::milliseconds(100));

//                 continue;
//             }

//             t_last = t_now;
//         }

//         // run the inference
//         {
//             whisper_full_params wparams = whisper_full_default_params(params.beam_size > 1 ? WHISPER_SAMPLING_BEAM_SEARCH : WHISPER_SAMPLING_GREEDY);
            
//             // 是否显示进度条
//             wparams.print_progress   = false;
//             // 是否打印特殊标记 ，如如 <|endoftext|>）
//             wparams.print_special    = params.print_special;
//             // 一边翻译一边打印还是全部处理完之后再打印
//             wparams.print_realtime   = false;
//             // 是否打印时间戳
//             wparams.print_timestamps = !params.no_timestamps;
//             // 是否将非英文文本翻译成英文
//             wparams.translate        = params.translate;
//             // 如果 未使用 VAD（端点检测），则将整个音频作为一个 segment 处理
//             // 如果 使用 VAD，则会切分语音段
//             wparams.single_segment   = !use_vad;
//             // 限制最大 token 数，防止生成过长的文本。
//             wparams.max_tokens       = params.max_tokens;
//             // 指定语言，如 "en"、"zh" 等
//             wparams.language         = params.language.c_str();
//             // 使用多少cpu线程进行推理
//             wparams.n_threads        = params.n_threads;
//             // 搜索策略
//             wparams.beam_search.beam_size = params.beam_size;
//             // 指定音频上下文窗口大小，0 表示使用全部数据
//             wparams.audio_ctx        = params.audio_ctx;
//             // 是否启用 TinyDiarize 进行说话人分割。
//             wparams.tdrz_enable      = params.tinydiarize; // [TDRZ]

//             // disable temperature fallback
//             //wparams.temperature_inc  = -1.0f;
//             wparams.temperature_inc  = params.no_fallback ? 0.0f : wparams.temperature_inc;

//             // 如果 no_context = true，则不提供上下文，识别时不考虑历史语音。
//             wparams.prompt_tokens    = params.no_context ? nullptr : prompt_tokens.data();
//             // 如果 no_context = false，则提供历史 token，
//             // 增强连续语音识别效果（适用于流式识别）
//             wparams.prompt_n_tokens  = params.no_context ? 0       : prompt_tokens.size();

//             // ctx 是 Whisper 处理的上下文
//             // pcm32.data() 是音频数据指针
//             // pcm32.size() 是样本数
//             if (whisper_full(ctx, wparams, pcmf32.data(), pcmf32.size()) != 0) {
//                 fprintf(stderr, "%s: failed to process audio\n", argv[0]);
//                 return 6;
//             }

//             // print result;
//             {
//                 if (!use_vad) {
//                     printf("\33[2K\r");

//                     // print long empty line to clear the previous line
//                     printf("%s", std::string(100, ' ').c_str());

//                     printf("\33[2K\r");
//                 } else {
//                     // 如果使用 vad 的话：
//                     // t1：当前时间与 t_start 的时间差（毫秒）
//                     const int64_t t1 = (t_last - t_start).count()/1000000;
//                     // t0：语音片段的起始时间，确保不会小于 0
//                     const int64_t t0 = std::max(0.0, t1 - pcmf32.size()*1000.0/WHISPER_SAMPLE_RATE);

//                     printf("\n");
//                     printf("### Transcription %d START | t0 = %d ms | t1 = %d ms\n", n_iter, (int) t0, (int) t1);
//                     printf("\n");
//                 }

//                 // whisper_full_n_segments(ctx) 获取文本片段数量，
//                 // 每个 segment 代表一段完整的话语
//                 const int n_segments = whisper_full_n_segments(ctx);
//                 for (int i = 0; i < n_segments; ++i) {
//                     const char * text = whisper_full_get_segment_text(ctx, i);

//                     if (params.no_timestamps) {
//                         printf("%s", text);
//                         fflush(stdout);

//                         if (params.fname_out.length() > 0) {
//                             fout << text;
//                         }
//                     } else {
//                         const int64_t t0 = whisper_full_get_segment_t0(ctx, i);
//                         const int64_t t1 = whisper_full_get_segment_t1(ctx, i);

//                         std::string output = "[" + to_timestamp(t0, false) + " --> " + to_timestamp(t1, false) + "]  " + text;

//                         if (whisper_full_get_segment_speaker_turn_next(ctx, i)) {
//                             output += " [SPEAKER_TURN]";
//                         }

//                         output += "\n";

//                         printf("%s", output.c_str());
//                         fflush(stdout);

//                         if (params.fname_out.length() > 0) {
//                             fout << output;
//                         }
//                     }
//                 }

//                 if (params.fname_out.length() > 0) {
//                     fout << std::endl;
//                 }

//                 if (use_vad) {
//                     printf("\n");
//                     printf("### Transcription %d END\n", n_iter);
//                 }
//             }

//             ++n_iter;

//             if (!use_vad && (n_iter % n_new_line) == 0) {
//                 printf("\n");

//                 // keep part of the audio for next iteration to try to mitigate word boundary issues
//                 pcmf32_old = std::vector<float>(pcmf32.end() - n_samples_keep, pcmf32.end());

//                 // Add tokens of the last full length segment as the prompt
//                 if (!params.no_context) {
//                     prompt_tokens.clear();

//                     const int n_segments = whisper_full_n_segments(ctx);
//                     for (int i = 0; i < n_segments; ++i) {
//                         const int token_count = whisper_full_n_tokens(ctx, i);
//                         for (int j = 0; j < token_count; ++j) {
//                             prompt_tokens.push_back(whisper_full_get_token_id(ctx, i, j));
//                         }
//                     }
//                 }
//             }
//             fflush(stdout);

//         }// end of 'run the inference'

//     }// end of 'while(is_running)'

//     audio.pause();

//     whisper_print_timings(ctx);
//     whisper_free(ctx);

//     return 0;
// }